<?php

class Crud_Section extends Base_AdminSectionRow 
{
	/**
	 * Columns array. Key is column name. And value is AdminSectionPropertyRow object.
	 * 
	 * @var array
	 */
	protected $_columns = null;
	
	/**
	 * Related section peer.
	 * 
	 * @var Db_Peer
	 */
	protected $_peer;
	
	/**
     * Fetches a new blank row (not from the database).
     * 
     * @return Crud_Db_Table_Row
     */
	public function createRow()
	{
		$row = $this->getPeer()->createRow();
		$row = new Crud_Section_Row($this, $row);
		return $row;
	}
	
	/**
	 * Get table metadata.
	 * 
	 * @return array
	 */
	public function getMetadata()
	{
		$filter = new Filter_StringToPeer();
		$class = $filter->filter($this->getTableName());
		
		$peer = call_user_func(array($class, 'getInstance'));
		$metadata = $peer->info(Zend_Db_Table::METADATA);
		return $metadata;
	}
	
	/**
	 * Get the map.
	 * 
	 * @return array
	 */
	public function getMap()
	{
		$peer = $this->getPeer();
		$map = $peer->info(Zend_Db_Table::REFERENCE_MAP);
		return $map;
	}
	
	/**
	 * Return related section peer. 
	 * 
	 * @return Db_Peer
	 */
	public function getPeer()
	{
		if ($this->_peer) {
			return $this->_peer;
		}
		
		$filter = new Filter_StringToPeer();
		$class = $filter->filter($this->getTableName());
		
		$this->_peer = call_user_func(array($class, 'getInstance'));
		return $this->_peer;
	}
	
	/**
	 * Return dependent many2many tables list.
	 * 
	 * @return array
	 */
	public function getMany2ManyTables()
	{
		$dependentTables = $this->getDependentTables();
		
		$many2manyTables = array();
		foreach ($dependentTables as $name => $table) {
			if ($table->isMany2Many()) {
				$many2manyTables[$name] = $table;
			}
		}
		
		return $many2manyTables;
	}
	
	/**
	 * Return dependent many2many table by name.
	 * 
	 * @return Crud_Section
	 */
	public function getMany2ManyTable($name)
	{
		$tables = $this->getMany2ManyTables();
		if (!isset($tables[$name])) {
			throw new Crud_Exception("Many2many for table `{$this->getTableName()}` with name `$name` does not exists");
		}
		
		return $tables[$name];
	}
	
	/**
	 * Return dependent NOT many2many tables list.
	 * 
	 * @return array
	 */
	public function getNotMany2ManyTables()
	{
		$dependentTables = $this->getDependentTables();
		
		$notMany2manyTables = array();
		foreach ($dependentTables as $name => $table) {
			if (!$table->isMany2Many()) {
				$notMany2manyTables[$name] = $table;
			}
		}
		
		return $notMany2manyTables;
	}
	
	/**
	 * Return dependent tables list.
	 * 
	 * @return array
	 */
	public function getDependentTables()
	{
		$peer = $this->getPeer();
		$dependentTables = (array)$peer->info(Zend_Db_Table::DEPENDENT_TABLES);
		
		$keys = array();
		$filter = new Filter_PeerToTableName();
		foreach ($dependentTables as $class) {
			$key = $filter->filter($class);
			$keys[] = $key;
		}
		
		if (!$keys) return array();
		
		$select = $this->getTable()->select();
		$select->where(AdminSectionPeer::KEY . Db_Select::SQL_IN, $keys);
		$rowset = $this->getTable()->fetchAll($select);
		
		$return = array();
		foreach ($rowset as $row) {
			$return[ $row->getKey() ] = $row;
		}
		
		return $return;
	}
	
	/**
	 * Return true if table is many2many.
	 * 
	 * @return boolean
	 */
	public function isMany2Many()
	{
		$name = $this->getTableName();
		if ((false !== strpos($name, '2')) && substr($name, -1) != '2') {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Return array of table columns.
	 * Key is column db name. Value if Crud_Db_Table_Column object.
	 * 
	 * @return array
	 */
	public function getColumns()
	{
		if ($this->_columns !== null) {
			return $this->_columns;
		}
		
		$select = AdminSectionPropertyPeer::getInstance()->select();
		$select->order('order asc');
		$rowset = $this->getAdminSectionPropertyRowsetBySectionId($select);
		
		$this->_columns = array();
		foreach ($rowset as $row) {
			$this->_columns[ $row->getKey() ] = $row;
		}
		
		return $this->_columns;
	}

	/**
	 * Return true when table has column with given name.
	 * 
	 * @param string $column
	 * @return boolean
	 */
	public function hasColumn($column)
	{
		if ($this->_columns === null) $this->getColumns();
		if (isset($this->_columns[$column])) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Return single column object.
	 * 
	 * @param string $key
	 * @return Crud_Section_Column
	 */
	public function getColumn($key)
	{
		$columns = $this->getColumns();
		if (!isset($columns[$key])) {
			throw new Crud_Exception("Column `$key` is not exists");
		}
		
		return $columns[$key];
	}
	
	/**
	 * Return column for show in other tables as foreign key information.
	 * Try get it from config and use 'name' or 'key' by default.
	 * By default column if ID.
	 * 
	 * @return string
	 */
	public function getPrimaryFKColumn()
	{
		$column = $this->getMainProperty();
		
		if (!$column) {
			$columns = array_keys($this->getColumns());
			if (in_array('name', $columns)) {
				$column = 'name';
			} else if (in_array('key', $columns)) {
				$column = 'key';
			} else {
				$column = 'id';
			}
		}
		
		return $column;
	}
	
	/**
	 * Return column with foreign key for given table.
	 * 
	 * @param Crud_Section
	 * @return Crud_Section_Column
	 */
	public function getFKColumnFor(Crud_Section $table)
	{
		$columns = $this->getColumns();
		foreach ($columns as $column) {
			if (!$column->isFK()) {
				continue;
			}
			
			if ($column->getFKTable()->getTableName() == $table->getTableName()) {
				return $column;
			}
		}
		
		throw new Crud_Exception("Table `{$this->getTableName()}` has not foreign key on table `{$table->getTableName()}`");
	}
	
	/**
	 * Return first column with have not foreign key for given table.
	 * 
	 * @param Crud_Section
	 * @return Crud_Section_Column
	 */
	public function getFKColumnNotFor(Crud_Section $table)
	{
		$columns = $this->getColumns();
		foreach ($columns as $column) {
			if (!$column->isFK()) {
				continue;
			}
			
			if ($column->getFKTable()->getTableName() != $table->getTableName()) {
				return $column;
			}
		}
		
		throw new Crud_Exception("Table `{$this->getTableName()}` has not foreign except `{$table->getTableName()}`");
	}
	
}
